package cc.rengu.igas.route.core.realize.impl;

import cc.rengu.igas.route.common.constant.SmartRouteParamConstant;
import cc.rengu.igas.route.common.dao.MultiRatioWeightCfgMapper;
import cc.rengu.igas.route.common.dao.impl.MultiRatioWeightCfgMapperImpl;
import cc.rengu.igas.route.common.entity.MultiRatioWeightCfg;
import cc.rengu.igas.route.common.entity.RuleCfg;
import cc.rengu.igas.route.common.enums.RouteTxnNumEnum;
import cc.rengu.igas.route.common.enums.SmartRouteRspEnums;
import cc.rengu.igas.route.core.helper.RouterHelper;
import cc.rengu.igas.route.core.model.ProdInfoBean;
import cc.rengu.igas.route.core.model.RouterReq;
import cc.rengu.igas.route.core.realize.RouterChoice;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.dao.ChannelCallCfgMapper;
import cc.rengu.oltp.service.common.dao.DstChannelInfoMapper;
import cc.rengu.oltp.service.common.dao.DstTxnAuthCfgMapper;
import cc.rengu.oltp.service.common.dao.impl.ChannelCallCfgMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.DstChannelInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.DstTxnAuthCfgMapperImpl;
import cc.rengu.oltp.service.common.entity.ChannelCallCfg;
import cc.rengu.oltp.service.common.entity.DstChannelInfo;
import cc.rengu.oltp.service.common.entity.DstTxnAuthCfg;
import cc.rengu.oltp.service.common.entity.SysParam;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.utility.util.RedisUtil;
import cc.rengu.utility.base.StringUtil;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import com.alibaba.fastjson.JSON;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * 静态路由实现类
 *
 * @author xionglz
 * @version 1.0
 * @date 2020-03-23
 */
public class StaticRouterChoiceImpl implements RouterChoice {
    private RgLogger rglog = RgLog.getLogger(this.getClass().getName());

    @Override
    public List<ProdInfoBean> routerChoice(RuleCfg ruleCfg, RouterReq routerReq) throws Exception {
        List<ProdInfoBean> listProdInfo = new ArrayList<>();
        MultiRatioWeightCfgMapper multiRatioWeightCfgMapper = new MultiRatioWeightCfgMapperImpl();
        MultiRatioWeightCfg multiRatioWeightCfg = null;
        //根据InstId,ruleId 查询多路比例路由权重配置信息，优先从redis中查询
        try {
            String key = SmartRouteParamConstant.ROUTE_CONF_STATIC + ":" + ruleCfg.getInstId() + ":" + ruleCfg.getRuleId();
            String valueOfRedis = RedisUtil.onceGet(key);
            if (!StringUtil.isNullorEmpty(valueOfRedis)) {
                multiRatioWeightCfg = JSON.parseObject(valueOfRedis, MultiRatioWeightCfg.class);
            }
        } catch (Exception e) {
            //redis查询出错则直接查询数据库。
            rglog.error(StringUtil.ExceptionToString(e));
            rglog.debug("通过redis查询多路比例路由信息出错！");
        }
        //如果redis查询异常或者无数据，则去数据库中查询
        if (null == multiRatioWeightCfg) {
            List<MultiRatioWeightCfg> listMultiRatioWeightCfg = multiRatioWeightCfgMapper.getMultiRatioWeightCfg(
                    ruleCfg.getInstId(), ruleCfg.getRuleId());
            //数据库也查询不到
            if (null == listMultiRatioWeightCfg || listMultiRatioWeightCfg.isEmpty()) {
                rglog.error("机构<{}>静态路由规则id<{}>未配置明细路由规则", ruleCfg.getInstId(), ruleCfg.getRuleId());
                throw new BizException(SmartRouteRspEnums.ILL_SRC_CHANNEL_ERROR.getRespCode(),
                        SmartRouteRspEnums.ILL_SRC_CHANNEL_ERROR.getRespDesc());
            }
            //如果静态路由查询结果不为一条，则报错
            if (listMultiRatioWeightCfg.size() != 1) {
                throw new BizException(SmartRouteRspEnums.CONFIG_ERROR.getRespCode(),
                        SmartRouteRspEnums.CONFIG_ERROR.getRespDesc());
            }
            if (!RouterHelper.judgeCommonRecordStatus(listMultiRatioWeightCfg.get(0).getRuleStatus(),
                    listMultiRatioWeightCfg.get(0).getAuditStatus())) {
                rglog.error("机构<{}>静态路由规则id<{}>配置明细路由规则状态异常， 规则状态<{}>审计状态<{}>", ruleCfg.getInstId(),
                        ruleCfg.getRuleId(), listMultiRatioWeightCfg.get(0).getRuleStatus(), listMultiRatioWeightCfg.get(0).getAuditStatus());
                throw new BizException(SmartRouteRspEnums.ILL_SRC_CHANNEL_ERROR.getRespCode(),
                        SmartRouteRspEnums.ILL_SRC_CHANNEL_ERROR.getRespDesc());
            }
            multiRatioWeightCfg = listMultiRatioWeightCfg.get(0);
        }
        //根据机构标识与通道标识查询通道表,先查询Redis，未查询到及失败都降级
        String dstChannelKey = routerReq.getInstId().trim() + multiRatioWeightCfg.getDstChannelId().trim();
        DstChannelInfo dstChannelInfo = null;
        try {
            dstChannelInfo = JSON.parseObject(RedisUtil.hashGet(AppParamConstant.CHANNEL_ISS_INFO_CACHE, dstChannelKey), DstChannelInfo.class);
        } catch (Exception e) {
            //抓取redis的RuntimeException类型异常
            rglog.warn("读取redis异常{}", StringUtil.ExceptionToString(e));
        }
        if (null == dstChannelInfo) {
            DstChannelInfoMapper dstChannelInfoMapper = new DstChannelInfoMapperImpl();
            dstChannelInfo = dstChannelInfoMapper.selectDstChannelInfoByPrimaryKey(routerReq.getInstId().trim(), multiRatioWeightCfg.getDstChannelId().trim());
        }
        if (null == dstChannelInfo || !AppParamConstant.YES.equalsIgnoreCase(dstChannelInfo.getDstChannelStatus())) {
            rglog.error("支付通道<{}-{}>未配置或已停用！", multiRatioWeightCfg.getDstChannelId(), (null == dstChannelInfo) ? "" : dstChannelInfo.getDstChannelName());
            throw new BizException(SmartRouteRspEnums.NO_AVAILABLE_DST_CHANNEL_ERROR.getRespCode(),
                    SmartRouteRspEnums.NO_AVAILABLE_DST_CHANNEL_ERROR.getRespDesc());
        }
        //根据通道标识，通道交易码查询系统参数表获取对应实现类
        String type = SmartRouteParamConstant.PARAM_TYPE_PREFIX_CHANNEL_INSTANCE + dstChannelInfo.getDstChannelId();
        SysParamService sysParamService = new SysParamServiceImpl();
        String txnNum;
        //由于签约使用的是代收的路由方式，因此签约需要特殊处理
        if (RouteTxnNumEnum.PAYMENT_SIGN.getTxnNum().equals(routerReq.getTxnNum()) ||
                RouteTxnNumEnum.PAYMENT_SIGN_VERIFY.getTxnNum().equals(routerReq.getTxnNum())) {
            txnNum = routerReq.getTxnNum();
        } else {
            RouteTxnNumEnum txnNumEnum = RouteTxnNumEnum.getInstanceFromTxnGroup(routerReq.getTxnGroup());
            if (null == txnNumEnum) {
                rglog.error("根据渠道交易分组<{}>未找到通道交易", routerReq.getTxnGroup());
                throw new BizException(SmartRouteRspEnums.CONFIG_ERROR.getRespCode(), SmartRouteRspEnums.CONFIG_ERROR.getRespDesc());
            }
            txnNum = txnNumEnum.getTxnNum();
        }
        SysParam sysParam = sysParamService.getSysParamInfo(dstChannelInfo.getInstId(), type, txnNum);
        if (sysParam == null || cc.rengu.oltp.utility.util.StringUtil.isEmptyOrNull(sysParam.getParamValue())) {
            rglog.error("根据通道标识<{}>，渠道交易码<{}>未找到系统参数配置", type, txnNum);
            throw new BizException(SmartRouteRspEnums.CONFIG_ERROR.getRespCode(), SmartRouteRspEnums.CONFIG_ERROR.getRespDesc());
        }
        //查询redis，不存在或者失败再降级查询数据库
        ChannelCallCfgMapper channelCallCfgMapper = new ChannelCallCfgMapperImpl();
        List<ChannelCallCfg> channelCallCfgs = channelCallCfgMapper.selectChannelCallCfgByTxnNum(ruleCfg.getInstId(), SmartRouteParamConstant.IGRT,
                SmartRouteParamConstant.ALL, txnNum, SmartRouteParamConstant.STRING_TWO_ZERO);
        Optional.ofNullable(channelCallCfgs).orElseThrow(() -> {
            rglog.error("获取交易码映射表失败");
            return new BizException(SmartRouteRspEnums.CONFIG_ERROR.getRespCode(), SmartRouteRspEnums.CONFIG_ERROR.getRespDesc());
        });
        String dstChannelId = dstChannelInfo.getDstChannelId();
        if (null == dstChannelId) {
            rglog.info("获取支付通道失败");
            throw new BizException(SmartRouteRspEnums.CONFIG_ERROR.getRespCode(), SmartRouteRspEnums.CONFIG_ERROR.getRespDesc());
        }
        Optional<ChannelCallCfg> channelCallCfgOpt = channelCallCfgs.stream().filter(item -> dstChannelId.equals(item.getCallChannelId())).findFirst();
        if (!channelCallCfgOpt.isPresent()) {
            rglog.info("获取通道服务调用配置失败");
            throw new BizException(SmartRouteRspEnums.CONFIG_ERROR.getRespCode(), SmartRouteRspEnums.CONFIG_ERROR.getRespDesc());
        }
        ChannelCallCfg channelCallCfg = channelCallCfgOpt.get();
        //获取通道交易权限信息
        DstTxnAuthCfg dstTxnAuthCfg = null;
        String dstTxnAuthKey = SmartRouteParamConstant.ROUTE_CONF_DST_TXN_AUTH + ":" + channelCallCfg.getInstId() + ":" + channelCallCfg.getCallChannelId() + ":" + channelCallCfg.getCallChannelTxn();
        try {
            dstTxnAuthCfg = JSON.parseObject(RedisUtil.onceGet(dstTxnAuthKey), DstTxnAuthCfg.class);
        } catch (Exception e) {
            rglog.warn("redis中未查询到key<{}>通道交易权限信息", dstTxnAuthKey);
        }
        if (null == dstTxnAuthCfg) {
            //查询数据库
            DstTxnAuthCfgMapper dstTxnAuthCfgMapper = new DstTxnAuthCfgMapperImpl();
            dstTxnAuthCfg = dstTxnAuthCfgMapper.selectDstTxnAuthCfgByPrimaryKey(channelCallCfg.getInstId(), channelCallCfg.getCallChannelId(), channelCallCfg.getCallChannelTxn());
        }
        if (null == dstTxnAuthCfg) {
            rglog.warn("该通道<{}：{}：{}>没有配置支持智能路由的通道交易", channelCallCfg.getInstId(), channelCallCfg.getCallChannelId(), channelCallCfg.getCallChannelTxn());
            throw new BizException(SmartRouteRspEnums.CONFIG_ERROR.getRespCode(), SmartRouteRspEnums.CONFIG_ERROR.getRespDesc());
        }
        //静态路由不检查通道及通道交易的时间窗口等信息
        ProdInfoBean prodInfo = new ProdInfoBean();
        prodInfo.setDstChannelId(dstChannelInfo.getDstChannelId());
        prodInfo.setProdDesc(dstChannelInfo.getDstChannelName());
        prodInfo.setProdSts(dstChannelInfo.getDstChannelStatus());
        prodInfo.setDstChannelTxnImplClassName(sysParam.getParamValue());
        prodInfo.setDstChannelTxnNum(dstTxnAuthCfg.getChannelTxn());
        listProdInfo.add(prodInfo);
        return listProdInfo;
    }
}
